use tokio::{
    net::{TcpListener, TcpStream},
    sync::broadcast,
    time::sleep,
};

use crate::{cmd::Command, connection::Connection, db::Db, Result};
use std::{future::Future, time::Duration};

struct Listener {
    db: Db,
    listener: TcpListener,
}

impl Listener {
    pub async fn run(&self) -> Result<()> {
        info!("accepting inbound connections");

        loop {
            let socket = self.accept().await?;
            let mut handler = Handler {
                db: self.db.clone(),
                connection: Connection::new(socket),
            };

            tokio::spawn(async move {
                if let Err(err) = handler.run().await {
                    error!("connection error: {:?}", err);
                }
            });
        }
    }

    async fn accept(&self) -> Result<TcpStream> {
        let (socket, addr) = self.listener.accept().await?;
        info!("accept from: {:?}", addr);
        Ok(socket)
    }
}

struct Handler {
    db: Db,
    connection: Connection,
}

impl Handler {
    pub async fn run(&mut self) -> Result<()> {
        loop {
            if let Some(frame) = self.connection.read_frame().await? {
                let cmd = Command::from_frame(frame)?;
                debug!("cmd: {:?}", cmd);
                cmd.apply(&self.db, &mut self.connection).await?;
            } else {
                return Ok(());
            }
        }
    }
}

pub async fn run(listener: TcpListener, shutdown: impl Future) -> Result<()> {
    let server = Listener {
        db: Db::new(),
        listener,
    };

    tokio::select! {
        res = server.run() => {
            if let Err(err) = res {
                error!("error {:?}", err)
            }
        }
        _ = shutdown => {
            info!("shutdown...");
        }
    }

    Ok(())
}
